Podman - Mise en réseau host et conteneur sans racine (rootless)

Je suppose que vous êtes ici parce que vous souhaitez exécuter une application dans un conteneur Podman et y accéder depuis l'hôte.

Par exemple, vous exécutez Podman sur Linux et vous souhaitez pouvoir exécuter un composant dans un conteneur sans racine, tel qu'une base de données, un courtier de messages ou un cache de données, et y accéder depuis votre application.

Vous pouvez le faire avec la publication de ports, mais comment le faire sans avoir à le faire ?

Une solution consiste à choisir judicieusement votre option de mise en réseau. Il existe un mode réseau qui simplifie la mise en réseau de l'hôte. Jetons d'abord un coup d'œil aux modes réseau.

Voici une table des matières rapide pour que vous puissiez passer directement à la partie dont vous avez besoin :

Les modes réseau contrôlent la façon dont votre conteneur interagit avec d'autres systèmes

Pour une mise en réseau simple de conteneur à hôte, connectez votre conteneur au réseau hôte

Utiliser le réseau hôte pour accéder au port du conteneur depuis l'hôte

Sur le réseau hôte , un conteneur peut également accéder aux ports de l'hôte

Prochaines étapes

 

Les modes réseau contrôlent la façon dont votre conteneur interagit avec d'autres systèmes

Ce que vous devez savoir sur Podman, c'est que, comme docker , il dispose de plusieurs modes réseau différents .

Un mode modifie les capacités de mise en réseau du conteneur, comme les autres conteneurs avec lesquels il peut interagir ou s'il peut voir l'hôte.

Podman propose plusieurs modes réseau différents que vous pouvez définir sur un conteneur :

Mode

Ce qu'il fait

bridge

Crée une pile réseau sur le réseau de pont par défaut

none

Aucun réseau n'est mis en place

container:<id>

Utilise le même réseau qu'un autre conteneur avec IDid

host

Utilise la pile réseau de l'hôte

network-id

Utilise un réseau défini par l'utilisateur (que vous pouvez créer à l'aide de podman network create ...)

ns:<path>

Joint un espace de noms réseau trouvé au chemin<path>

private

Crée un nouvel espace de noms réseau pour le conteneur

slirp4netns

Crée une pile de réseau utilisateur avec slirp4netns(il s'agit de l'option par défaut pour les conteneurs sans racine.)

Comme vous pouvez le constater, il existe un éventail d'options époustouflant.

Le mode que j'ai mis en évidence, le hostmode, est la solution la plus simple pour la mise en réseau hôte-conteneur et conteneur-hôte. Nous verrons cela ensuite.

Pour une mise en réseau simple de conteneur à hôte, connectez votre conteneur au réseau hôte

En mode réseau 'hôte', un conteneur partage l' espace de noms réseau de l'hôte ; ce qui signifie qu'il partage la même interface réseau, les mêmes tables de routage, etc., de sorte qu'il peut "voir" les mêmes choses que l'hôte.

Pouvoir partager la même interface réseau et les mêmes tables de routage peut être très utile, car cela signifie que votre conteneur peut voir et accéder aux services comme s'il s'agissait d'un processus normal (non conteneur). Et votre hôte peut voir et accéder aux services exécutés dans des conteneurs.

Attention à la sécurité ! La connexion d'un conteneur au réseau hôte est généralement considérée comme non sécurisée , car votre conteneur peut essentiellement accéder à d'autres ports. Et cela vous expose à un tas de risques (OMG !)

La page de manuel ( man podman-run) convient également :

Remarque : le mode hôte donne au conteneur un accès complet aux services système locaux tels que D-bus et est donc considéré comme non sécurisé ;

Pour cette raison, il est préférable de l'utiliser uniquement dans le développement. Et vous ne devriez certainement pas l'utiliser pour exécuter des conteneurs en production.

Utiliser le réseau hôte pour accéder au port du conteneur depuis l'hôte

Voyons le réseau hôte en action, pour voir comment nous pouvons accéder à un service exécuté dans un conteneur, à partir de l'hôte.

Nous allons utiliser podman runpour exécuter un processus dans un nouveau conteneur sans racine, et ajouter --network=hostpour l'attacher au réseau hôte :

podman run --network=host nginxinc/nginx-unprivileged

Le serveur Web Nginx s'exécute maintenant sur le port 8080, à l'intérieur d'un conteneur.

(L' nginx-unprivilegedimage est une variante de l' nginximage standard, qui est configurée pour exécuter Nginx sur un port non privilégié.)

Si je vais dans mon navigateur Web sur l'hôte et que j'accède à http://localhost:8080 , je verrai la page d'accueil de nginx :

Navigateur Firefox affichant la page d'accueil de nginx sur localhost:8080Navigateur Firefox affichant la page d'accueil de nginx sur localhost:8080 
 

Lorsqu'un conteneur sans racine est connecté au réseau hôte, vous pouvez accéder à ses ports depuis l'extérieur du conteneur

Comment c'est? Je n'ai configuré aucune publication ou redirection de port… ..

Étant donné que le conteneur est connecté au hostréseau, il se lie à un port dans l'espace de noms réseau de l'hôte. C'est une autre façon de dire qu'il se lie à un port sur l'hôte.

Vous n'avez pas besoin de configurer de publication de port supplémentaire, ni de transfert, ni quoi que ce soit de ce genre. Avec le mode réseau hôte , le réseau est partagé entre l'hôte et le conteneur. Les éléments sur localhost dans le conteneur sont accessibles sur localhost à partir de l'hôte.

La tête haute! Puisque nous exécutons un conteneur sans racine , vous devez vous assurer que l'application n'essaie pas de se lier (s'exécuter) sur un port privilégié, comme le port 80 . S'il essaie de se lier à un port privilégié, vous verrez une erreur comme :

bind() à 0.0.0.0:80 a échoué (13 : autorisation refusée)

Vous devrez donc configurer votre application pour qu'elle se lie à un port non privilégié, qui est un numéro de port commençant par 1024 .

Pourquoi est-ce? Parce que vous exécutez en tant qu'utilisateur non privilégié (c'est-à-dire non root).

À partir des pages de manuel pour man 7 ip(il m'a fallu des siècles pour trouver exactement où cela est décrit dans les pages de manuel !):

Les numéros de port inférieurs à 1024 sont appelés ports privilégiés (ou parfois : ports réservés). Seul un processus privilégié (sous Linux : un processus qui a la capacité CAP_NET_BIND_SERVICE dans l'espace de noms utilisateur régissant son espace de noms réseau) peut lier(2) à ces sockets.

Sur le réseau hôte , un conteneur peut également accéder aux ports de l'hôte

Lorsque vous utilisez le mode réseau hôte , vous pouvez également accéder aux ports de l'hôte depuis l'intérieur du conteneur.

(C'est pourquoi il est considéré comme peu sûr.)

Sur mon système d'exploitation hôte, j'exécute le serveur Web Apache sur le port 80. J'utilise curlpour faire une demande au serveur et obtenir une petite page de test idiote que j'ai créée :

$ curl http://localhost:80

Hello, internet friend!

Que se passe-t-il maintenant lorsque j'exécute la même curl http://localhost:80commande, mais dans un conteneur configuré avec le mode réseau hôte ?

$ podman exec -it 8918c8ebbbfd curl http://localhost:80

Hello, internet friend!

J'obtiens le même résultat! Mon conteneur peut atteindre le serveur Web qui s'exécute sur mon hôte, en utilisant simplement localhost.

Ainsi, lorsqu'un conteneur sans racine utilise le mode réseau hôte , il peut également accéder aux ports de l'hôte en utilisant l'adresse localhost .

Prochaines étapes

J'espère que vous avez tiré 🌠 VALUE 🌠 de cet article et qu'il vous a permis de gagner du temps lors de la configuration des ports et de la mise en réseau avec vos conteneurs Podman sans racine.

N'oubliez pas que vous ne devriez pas vraiment l'utiliser en production. Mais c'est un gain de temps pour le développement et vous permet d'exécuter très facilement des logiciels dans des conteneurs sans vous soucier de la publication de ports.